<template>
  <el-tree
    ref="tree"
    :key="treeKey"
    draggable
    :allow-drop="allowDrop"
    :allow-drag="allowDrag"
    show-checkbox
    node-key="prop"
    :data="renderColoums"
    :props="defaultProps"
    :default-checked-keys="defaultCheckedKeys"
    @check="check"
    @node-drop="handleDrop"
    @check-change="currentChange"
  />
</template>

<script>
export default {
  props: {
    columns: {
      type: Array,
      default: () => []
    },
    // 重置的时候是否需要重置排序， 正常只是重置选中
    resetSort: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      // 列设置组件key
      treeKey: 1,
      renderColoums: [],
      // 列设置中 tree配置
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      checkedAll: [], // 全选时的 key
      checkedNull: [], // 全不选时的 key
      defaultSelect: [], // 选中项列表
      defaultCheckedKeys: [], // 列设置默认选中的节点
      defaultColoums: [] // 初始的 colums 顺序
    }
  },
  created() {
    this.columnsHanlder()
    this.checkedAll = ['all', ...this.columns.map((item) => item.prop)]
    this.checkedNull = this.columns.filter((item) => item.disabled).map((item) => item.prop)
    this.defaultCheckedKeys = this.checkedAll
    this.defaultSelect = this.checkedAll
  },
  methods: {
    // 父组件重置事件，调用子组件重置
    resetTree() {
      this.treeKey++
      this.defaultCheckedKeys = this.checkedAll // 重置列设置
      this.defaultSelect = this.checkedAll
      if (!this.resetSort) return
      this.renderColoums = [...this.defaultColoums]
      this.updateOrder(this.columns, this.renderColoums.slice(1))
    },
    // 处理 列设置的 columns 去掉 多选和 操作部分 ， 把 多选和操作部分的 disabled 赋值
    columnsHanlder() {
      this.renderColoums = this.columns.filter((item) => {
        if (item?.hide) {
          item.show = false
        }
        if (item.prop === 'selection' || item.prop === 'actions') {
          item.disabled = true
        }
        return item.prop !== 'selection' && item.prop !== 'actions' && !item?.hide
      })
      this.renderColoums.unshift({
        label: '全选',
        prop: 'all',
        draggable: false,
        show: true
      })
      this.defaultColoums = [...this.renderColoums]
    },
    // 只有点击的时候才会触发
    check(data, checkNodes) {
      // 点击的时候获取选中的节点，更改defaultSelect
      this.defaultSelect = checkNodes.checkedKeys // 选中的节点
    },
    // Tree 拖动时更新表格
    handleDrop(before, after, inner, event) {
      this.updateOrder(this.columns, this.renderColoums.slice(1))
      this.$nextTick(() => {
        this.$refs.tree.setCheckedKeys(this.defaultSelect)
      })
    },
    // 判断节点能否被放置 ， inner 用来防止把节点放在子级 , dropNode 用来防止把节点放在全选前面
    allowDrop(draggingNode, dropNode, type) {
      if (type === 'inner') return false
      return dropNode.data?.draggable !== false
    },
    // 判断节点能否被拖拽
    allowDrag(node) {
      const { data } = node
      if (data?.label === '全选') return false
      return true
    },
    // 拖拽以后更新顺序
    updateOrder(a, b) {
      // console.log('this.defaultColoums',a, b);
      const resultMap = new Map()
      // 将 b 数组的每个项的 prop 和索引保存到 resultMap 中
      b.forEach((item, index) => {
        resultMap.set(item.prop, index)
      })
      // 根据 b 数组的顺序对 a 数组进行排序
      a.sort((item1, item2) => {
        const index1 = resultMap.get(item1.prop)
        const index2 = resultMap.get(item2.prop)
        // 如果无法找到对应的索引，则保持原始顺序
        if (index1 === undefined || index2 === undefined) {
          return 0
        }
        return index1 - index2
      })
    },
    // 列设置选中事件
    currentChange(e, d) {
      const { prop } = e
      if (prop === 'all') {
        this.columns.forEach((item) => {
          if (item.disabled) return
          if (item.hide) {
            item.show = false
          } else {
            item.show = d
          }
        })
        this.treeKey++
        if (d) {
          this.defaultSelect = this.checkedAll
          this.defaultCheckedKeys = this.checkedAll
        } else {
          this.defaultSelect = this.checkedNull
          this.defaultCheckedKeys = this.checkedNull
        }
        return
      }
      const obj = this.columns.find((it) => it.prop === e.prop)
      if (obj.hide) {
        obj.show = false
      } else {
        obj.show = d
      }
    }
  }
}
</script>
<style lang="scss" scoped>

</style>
